#include "asgkaBase.h"
#include "global.h"
#include "asgka_space.h"
#include "singleMember.h"
#include "messageCiphertext.h"
#include "asgka_network.h"
#include "asgka_wnd_message.h"
#include "common.h"

asgkaBase::asgkaBase()
:m_group(NULL)
{
	asgka_malloc(m_my_plaintext);
}

asgkaBase::asgkaBase(singleGroup *group)
:m_group(group)
{
	asgka_malloc(m_my_plaintext);
	
	if (localname.compare(m_group->getGroupLeader()->getMemberName()))
	{
		asgka_malloc(m_my_decrypt_key);
	}
	else
	{
		asgka_malloc(m_my_groupKeyR);
		asgka_malloc(m_my_groupKeyA);
	}
}

asgkaBase::~asgkaBase()
{
	asgka_free(m_my_plaintext);
	
	if (localname.compare(m_group->getGroupLeader()->getMemberName()))
	{
		asgka_free(m_my_decrypt_key);
	}
	else
	{
		asgka_free(m_my_groupKeyR);
		asgka_free(m_my_groupKeyA);
	}
}

void asgkaBase::correlateAGroup(singleGroup *group)
{
	m_group = group;

	if (localname.compare(m_group->getGroupLeader()->getMemberName()))
	{
		asgka_malloc(m_my_decrypt_key);
	}
	else
	{
		asgka_malloc(m_my_groupKeyR);
		asgka_malloc(m_my_groupKeyA);
	}
}

void asgkaBase::generateAgreementKey()
{
	randomG1(m_my_plaintext, LENGTH);
	m_group->setPlaintext(m_my_plaintext);
}

void asgkaBase::computeAgreedKey()
{
	asgka_element ciphertext1;
	asgka_element ciphertext2;
	asgka_element ciphertext3;
	asgka_element otherpubH;
	
	asgka_malloc(ciphertext1);
	asgka_malloc(ciphertext2);
	asgka_malloc(ciphertext3);
	asgka_malloc(otherpubH);

	memcpy(ciphertext1, m_group->getAddrofCiphertext1(), LENGTH);
	memcpy(ciphertext2, m_group->getAddrofCiphertext2(), LENGTH);
	memcpy(ciphertext3, m_group->getAddrofCiphertext3(), LENGTH);
	memcpy(otherpubH, m_group->getAddrofPubH(), LENGTH);
	decryption(m_my_plaintext, ciphertext1, ciphertext2, ciphertext3, 
		m_my_decrypt_key, otherpubH, LENGTH);

	asgka_free(ciphertext1);
	asgka_free(ciphertext2);
	asgka_free(ciphertext3);
	asgka_free(otherpubH);
}

void asgkaBase::publicCiphertexts()
{
	asgka_element ciphertext1;
	asgka_element ciphertext2;
	asgka_element ciphertext3;

	asgka_malloc(ciphertext1);
	asgka_malloc(ciphertext2);
	asgka_malloc(ciphertext3);

	computeMyGroupKeyR();
	computeMyGroupKeyA();

	encryption(ciphertext1, ciphertext2, ciphertext3, 
		m_my_groupKeyR, m_my_groupKeyA, m_my_plaintext, LENGTH);

	// Public them
	messageBase *message = new messageCiphertext(m_group->getGroupName(), 
		ciphertext1, ciphertext2, ciphertext3);

	const std::map<std::string, singleMember *> *member_list = m_group->getAddrofMemberlist();
	std::map<std::string, singleMember *>::const_iterator it = member_list->begin();
	for (; it != member_list->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		sendMessageToMember_tcp(message, it->second);
	}
	delete message;

	asgka_free(ciphertext1);
	asgka_free(ciphertext2);
	asgka_free(ciphertext3);
}

void asgkaBase::updateElementsofGroup() const
{
	m_group->setPlaintext(m_my_plaintext);
	std::string strupdate("Update the key of the group named ");
	strupdate.append(m_group->getGroupName());
	strupdate.append("\r\n");
	if (localname.compare(m_group->getGroupLeader()->getMemberName()))
	{
		strupdate.append("\r\n The decrypt key \r\n");
		m_group->setDecryptKey(m_my_decrypt_key);
		strupdate.append(m_my_decrypt_key, LENGTH);
		strupdate.append("\r\n");
	}
	else
	{
		strupdate.append("\r\n The groupKeyR \r\n");
		m_group->setGroupKeyR(m_my_groupKeyR);
		strupdate.append(m_my_groupKeyR, LENGTH);
		strupdate.append("\r\n");
		strupdate.append("\r\n The groupKeyA \r\n");
		m_group->setGroupKeyA(m_my_groupKeyA);
		strupdate.append(m_my_groupKeyA, LENGTH);
		strupdate.append("\r\n");
	}
	strupdate.append("\r\nThe Agreed key\r\n");
	strupdate.append(m_my_plaintext, LENGTH);
	strupdate.append("\r\n");
	newLog(strupdate);
	std::string groupname = m_group->getGroupName();
	char *name = new char[groupname.size() + 1];
	asgka_element ptxt;
	memset(name, 0, groupname.size() + 1);
	asgka_malloc(ptxt);
	memcpy(name, groupname.c_str(), groupname.size());
	memcpy(ptxt, m_group->getAddrofPlaintext(), LENGTH);
	SendMessageA(gWnd, ASGKA_AGR_COM,(WPARAM)name, (LPARAM)ptxt);
}

c_asgka_element asgkaBase::getAgreedKey() const 
{
	return m_my_plaintext;
}
